﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TaskLiskFullscreen
{
    internal class HotkeyListener : UserControl
    {
        /// <summary>
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源，为 true；否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region 组件设计器生成的代码

        /// <summary>
        /// 设计器支持所需的方法 - 不要修改
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // HotkeyListener
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.DoubleBuffered = true;
            this.Name = "HotkeyListener";
            this.Size = new System.Drawing.Size(30, 30);
            this.Load += new System.EventHandler(this.UserControl1_Load);
            this.ResumeLayout(false);

        }

        #endregion

        public HotkeyListener()
        {
            InitializeComponent();
        }
        bool hasFocus = false;
        private void UserControl1_Load(object sender, EventArgs e)
        {
            if (!DesignMode)
            {
                Visible = false;
                ParentForm.Deactivate += ParentForm_LostFocus;
                ParentForm.Shown += ParentForm_GotFocus;
                ParentForm.Activated += ParentForm_GotFocus;
                ParentForm.Closed += ParentForm_Closed;
                ParentForm.Load += ParentForm_Load;
            }
            if (DesignMode)
            {
                this.SizeChanged += HotkeyListener_SizeChanged;
            }
        }

        private void ParentForm_Load(object sender, EventArgs e)
        {
            updateHotkey();
        }

        private void HotkeyListener_SizeChanged(object sender, EventArgs e)
        {
            this.Size = new Size(32, 32);
        }

        Dictionary<int, HotKey> hotkeys = new Dictionary<int, HotKey>();

        private void ParentForm_GotFocus(object sender, EventArgs e)
        {
            hasFocus = true;
            updateHotkey();
        }

        private int hkid = 0x0;
        public void AddHotkey(HotKey hotKey)
        {
            int id = hkid++;
            hotKey.id = id;
            hotkeys.Add(id, hotKey);
            updateHotkey();
        }

        public void ClearHotkey(HotKey hotKey)
        {
            IEnumerable<HotKey> keys = hotkeys.Values.Where(v => v.Name == hotKey.Name).ToList();
            keys.ToList().ForEach(k => hotkeys.Remove(k.id));
            updateHotkey();
        }

        public void ClearHotkey()
        {
            hotkeys.Clear();
            updateHotkey();
        }

        private void updateHotkey()
        {
            if (!IsHandleCreated) { return; }
            hotkeys.Keys.ToList().ForEach(k => UnregisterHotKey(this.Handle, k));
            hotkeys.Values.ToList().ForEach(k => {
                //Console.WriteLine("" + k.Name + " " + k.persist + " " + hasFocus);
                if (k.persist || hasFocus)
                {
                    RegisterHotKey(Handle, k.id, k.KeyModifier, k.Key);
                }
            });
        }

        private void ParentForm_LostFocus(object sender, EventArgs e)
        {
            hasFocus = false;
            updateHotkey();
        }
        private void ParentForm_Closed(object sender, EventArgs e)
        {
            hotkeys.Keys.ToList().ForEach(k => UnregisterHotKey(this.Handle, k));
        }
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_HOTKEY)
            {
                int which = m.WParam.ToInt32();
                if (hotkeys.ContainsKey(which))
                {
                    hotkeys[which].Action(hotkeys[which]);
                }
                return;
            }
            base.WndProc(ref m);
        }

        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hwnd, int id, KeyModifier fsModifiers, Keys vk);
        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hwnd, int id);
        [DllImport("kernel32.dll", EntryPoint = "GlobalAddAtomA")]
        private static extern Int16 GlobalAddAtom(string lpString);
        private const int WM_HOTKEY = 0x312;
        private const int MOD_ALT = 0x1;
        private const int MOD_CONTROL = 0x2;
        private const int MOD_SHIFT = 0x4;
        private const int MOD_WIN = 0x8;

        protected override void OnPaintBackground(PaintEventArgs e)
        {
            base.OnPaint(e);
            if (Visible)
            {
                e.Graphics.Clear(BackColor);
            }
        }

    }


    public enum KeyModifier
    {
        None = 0x0,
        Alt = 0x1,
        Ctrl = 0x2,
        Shift = 0x4,
        Win = 0x8
    }

    public class HotKey
    {
        internal int id = -1;
        public string Name;
        public KeyModifier KeyModifier;
        public Keys Key;
        public Action<HotKey> Action;
        internal bool persist = false;
        public HotKey(string name, KeyModifier keyModifier, Keys key, Action<HotKey> action)
        {
            this.Name = name;
            KeyModifier = keyModifier;
            Key = key;
            Action = action;
        }
        public HotKey(string name, KeyModifier keyModifier, Keys key, bool persistKey, Action<HotKey> action)
        {
            this.Name = name;
            KeyModifier = keyModifier;
            Key = key;
            Action = action;
            this.persist = persistKey;
        }
    }
}
